package com.hbnrtech.sip.gb28181.handler;

import com.hbnrtech.sip.dao.mapper.SipDeviceChannelMapper;
import com.hbnrtech.sip.dao.mapper.SipDeviceMapper;
import com.hbnrtech.sip.dao.model.SipDeviceChannel;
import com.hbnrtech.sip.gb28181.handler.dto.CatalogItem;
import com.hbnrtech.sip.gb28181.handler.dto.CatalogResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.sip.RequestEvent;
import javax.sip.ServerTransaction;
import javax.sip.message.Response;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.io.StringReader;
import java.math.BigDecimal;
import java.util.List;

/**
 * @author liuduo
 * @date 2025-04-22 16:22
 */
@Component
@Slf4j
public class CatalogResponseHandler extends SipHandler{
    @Autowired
    private SipDeviceChannelMapper sipDeviceChannelMapper;
    @Autowired
    private SipDeviceMapper sipDeviceMapper;

    // JAXBContext 是线程安全的，可以缓存
    private static final JAXBContext jaxbContext;

    static {
        try {
            // 初始化 JAXBContext
            jaxbContext = JAXBContext.newInstance(CatalogResponse.class);
        } catch (JAXBException e) {
            log.error("Failed to initialize JAXBContext for CatalogResponse", e);
            // 如果初始化失败，应用可能无法正常处理目录响应
            throw new RuntimeException("JAXBContext initialization failed", e);
        }
    }

    /**
     * 处理收到的 Catalog XML 响应内容.
     */
    public void handleCatalogResponse(String xmlContent, RequestEvent requestEvent, ServerTransaction serverTransaction) {
        try {
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

            // 反序列化 XML
            StringReader reader = new StringReader(xmlContent);
            CatalogResponse catalogResponse = (CatalogResponse) unmarshaller.unmarshal(reader);

            // 检查基本信息和 DeviceList
            if (catalogResponse == null || !"Catalog".equalsIgnoreCase(catalogResponse.getCmdType())) {
                log.error("Invalid Catalog response: CmdType mismatch or null response.");
                return;
            }

            if (catalogResponse.getDeviceList() == null || catalogResponse.getDeviceList().getItems() == null) {
                log.info("Catalog response for device {} (SN: {}) contains an empty DeviceList.",
                        catalogResponse.getDeviceId(), catalogResponse.getSn());
                // 如果设备确实没有通道，这是正常情况，清空该设备下的旧通道（如果需要）
                clearDeviceChannels(catalogResponse.getDeviceId());
                return;
            }

            // 父设备 ID
            String parentDeviceId = catalogResponse.getDeviceId();
            List<CatalogItem> items = catalogResponse.getDeviceList().getItems();
            log.info("Received {} channel items for device {}", items.size(), parentDeviceId);

            // 遍历 Item 列表并写入/更新数据库
            for (CatalogItem item : items) {
                SipDeviceChannel channel = convertCatalogItemToDeviceChannel(item, parentDeviceId);
                SipDeviceChannel dbSipChannel = sipDeviceChannelMapper.selectByPrimaryKey(channel.getChannelId());
                if (dbSipChannel != null) {
                    sipDeviceChannelMapper.updateByPrimaryKeySelective(channel);
                } else {
                    sipDeviceChannelMapper.insertSelective(channel);
                }
            }
            Response response = getMessageFactory().createResponse(Response.OK, requestEvent.getRequest());
            serverTransaction.sendResponse(response);
        } catch (Exception e) {
            // 捕获其他潜在异常
            log.error("An unexpected error occurred during Catalog processing.", e);
            // 抛出运行时异常，让 @Transactional 回滚
            throw new RuntimeException("Catalog processing failed", e);
        }
    }

    /**
     * 将 JAXB DTO CatalogItem 转换为数据库实体 DeviceChannel.
     */
    private SipDeviceChannel convertCatalogItemToDeviceChannel(CatalogItem item, String parentDeviceId) {
        // 使用 @Builder 构建 DAO 对象
        return SipDeviceChannel.builder()
                .channelId(item.getChannelId()) // 通道 ID 来自 Item 的 DeviceID
                .deviceId(parentDeviceId)     // 设备 ID 来自 Response 的 DeviceID
                .name(item.getName())
                .parentId(item.getParentId()) // 父节点 ID
                .manufacturer(item.getManufacturer())
                .model(item.getModel())
                .owner(item.getOwner())
                .civilCode(item.getCivilCode())
                .address(item.getAddress())
                .parental(item.getParental() != null ? item.getParental() : 0) // 提供默认值
                .safetyWay(item.getSafetyWay())
                .registerWay(item.getRegisterWay() != null ? item.getRegisterWay() : 1) // 提供默认值
                .secrecy(item.getSecrecy() != null ? item.getSecrecy() : 0)     // 提供默认值
                .status(item.getStatus() != null ? item.getStatus() : "ON")     // 提供默认值
                .longitude(parseBigDecimal(item.getLongitudeStr())) // 转换经纬度
                .latitude(parseBigDecimal(item.getLatitudeStr()))
                .ptzType(item.getPtzType())// ptzType 如果需要的话，类似处理
                .build();
    }

    /**
     * 安全地将字符串解析为 BigDecimal.
     */
    private BigDecimal parseBigDecimal(String value) {
        if (value == null || value.trim().isEmpty()) {
            return null;
        }
        try {
            // 移除可能的空白字符
            return new BigDecimal(value.trim());
        } catch (NumberFormatException e) {
            log.warn("Could not parse string '{}' as BigDecimal.", value);
            return null;
        }
    }

    /**
     * 清理指定设备下的所有旧通道记录。 在接收到新的完整 Catalog 列表时调用，确保只保留最新信息。
     */
    private void clearDeviceChannels(String deviceId) {
        int deletedCount = sipDeviceChannelMapper.deleteByDeviceId(deviceId);
        log.info("Cleared {} old channels for device {}", deletedCount, deviceId);
    }
}
